﻿using System;

namespace PC1
{
    public class Alu : IAlu
    {
        private int _rIn0;

        private int _rIn1;

        private int _rOut0;

        private AluState _rState;

        public void Add()
        {
            ResetState();
            checked
            {
                try
                {
                    _rOut0 = _rIn0 + _rIn1;
                }
                catch (OverflowException)
                {
                    SetOverflow();
                }
            }
            IfSetNegative();
            IfSetZero();
        }

        public void And()
        {
            ResetState();
            _rOut0 = _rIn0 & _rIn1;
            IfSetNegative();
            IfSetZero();
        }

        public void Cmp()
        {
            if (_rIn0 == _rIn1)
            {
                _rState = AluState.Zero;
            }
            else if (_rIn0 < _rIn1)
            {
                _rState = AluState.Negative;
            }
            else
            {
                _rState = AluState.Positive;
            }
        }

        public int GetROut0()
        {
            return _rOut0;
        }

        public void Or()
        {
            ResetState();
            _rOut0 = _rIn0 | _rIn1;
            IfSetNegative();
            IfSetZero();
        }

        public void SetRIn0(int v)
        {
            _rIn0 = v;
        }

        public void SetRIn1(int v)
        {
            _rIn1 = v;
        }

        public void Sub()
        {
            ResetState();
            checked
            {
                try
                {
                    _rOut0 = _rIn0 - _rIn1;
                }
                catch (OverflowException)
                {
                    SetOverflow();
                }
            }
            IfSetNegative();
            IfSetZero();
        }

        public void Xor()
        {
            ResetState();
            _rOut0 = _rIn0 ^ _rIn1;
            IfSetNegative();
            IfSetZero();
        }

        public AluState GetRState()
        {
            return _rState;
        }

        private void IfSetNegative()
        {
            if (_rOut0 < 0)
            {
                _rState |= AluState.Negative;
            }
        }

        private void IfSetZero()
        {
            if (_rOut0 == 0)
            {
                _rState |= AluState.Zero;
            }
        }

        private void ResetState()
        {
            _rState = AluState.Undefined;
        }

        private void SetOverflow()
        {
            _rState |= AluState.Overflow;
        }

        /*
(for left)

(original << bits) | (original >> (32 -bits))
or

(for right)

(original >> bits) | (original << (32 -bits))
        */ 
    }
}